home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_08_09
/
8n09097a
< prev
next >
Wrap
Text File
|
1990-07-25
|
17KB
|
590 lines
/*------------------------------------------------
XMODEMR.C
Author Date Description
-------------------------------------------
Jon Ward 22 Apr 90 Initial Revision.
Jon Ward 23 Apr 90 Cleanup and modify for
XMODEM-1K and XMODEM-CRC.
Jon Ward 26 Apr 90 Corrected implementation
of XMODEM-CRC.
Jon Ward 7 Jun 90 Added more comments and a
little cleanup.
------------------------------------------------*/
#define XMODEM_LIB 1
#include <stdio.h>
#include "xmodem.h"
#define STATIC static /* undef for debugging */
/*------------------------------------------------
------------------------------------------------*/
struct send_n_wait_st
{
char char_to_send;
int retry_count;
long ms_timeout;
unsigned char *valid_responses;
int num_valid_responses;
};
STATIC unsigned char soh_stx_can [] =
{ SOH, STX, CAN };
STATIC unsigned char soh_stx_can_eot [] =
{ SOH, STX, CAN, EOT };
STATIC struct send_n_wait_st crc_req =
{
'C',
CRC_RETRY_COUNT,
CRC_TIMEOUT,
soh_stx_can,
sizeof (soh_stx_can)
};
STATIC struct send_n_wait_st checksum_req =
{
NAK,
NAK_RETRY_COUNT,
NAK_TIMEOUT,
soh_stx_can,
sizeof (soh_stx_can)
};
STATIC struct send_n_wait_st pack_nak =
{
NAK,
NAK_RETRY_COUNT,
NAK_TIMEOUT,
soh_stx_can_eot,
sizeof (soh_stx_can_eot)
};
STATIC struct send_n_wait_st pack_ack =
{
ACK,
ACK_RETRY_COUNT,
ACK_TIMEOUT,
soh_stx_can_eot,
sizeof (soh_stx_can_eot)
};
/*------------------------------------------------
Error messages for error enums.
------------------------------------------------*/
STATIC char *xmodem_errors [] =
{
"Transmission Successful",
"NULL Transmit function pointer",
"NULL Receive function pointer",
"Receiver cancelled the transfer",
"Sender cancelled the transfer",
"User cancelled the transfer",
"Error reading the file",
"Error writing the file",
"Timed out waiting for data pack ACK",
"Timed out waiting for initial NAK",
"Timed out waiting for SOH",
"Timed out waiting for data",
"Timed out waiting for final ACK",
"Invalid char waiting for SOH",
"Block mismatch in packet header",
"CRC is incorrect",
"Checksum is incorrect",
"Block out of sequence",
"Received character error",
"Modem is not online",
};
/*------------------------------------------------
Local Function Prototypes
------------------------------------------------*/
STATIC int xm_send_n_wait (
const struct send_n_wait_st *req, /* request structure */
unsigned char *response, /* response from sender */
xfunc *xmf); /* xmodem external functions */
STATIC int xm_block_start (
xblock *xb, /* xmodem block data */
unsigned char block_start, /* block start char from sender */
xfunc *xmf); /* xmodem external functions */
STATIC int xm_recv_block (
xblock *xb, /* xmodem block data */
register xfunc *xmf); /* xmodem external functions */
/*------------------------------------------------
This function receives a file transferred via
XMODEM, XMODEM-1K or XMODEM/CRC. The f argument
represents the file to receive that has been
opened for writing.
------------------------------------------------*/
int xmodem_recv (
FILE *f, /* file to write to */
int (*transmit) (char), /* xmit function */
int (*receive) (long, unsigned int *), /* recv function */
void (*dispstat) (long, long, const char *), /* display function */
int (*check_abort) (void)) /* manual abort function */
{
register int error; /* gen purpose error var */
unsigned char start_char; /* first char of block */
unsigned char next_block; /* next block we expect */
unsigned char last_block; /* last successful block */
xblock xb; /* xmodem block data */
xfunc xmfuncs; /* xmodem external functions */
/*------------------------------------------------
Initialize the function pointer structure.
------------------------------------------------*/
if ((xmfuncs.dispstat = dispstat) == NULL)
xmfuncs.dispstat = xm_no_disp_func;
if ((xmfuncs.check_abort = check_abort) == NULL)
xmfuncs.check_abort = xm_no_abort_func;
if ((xmfuncs.transmit = transmit) == NULL)
return (xm_perror (XERR_XMIT_FUNC, &xmfuncs));
if ((xmfuncs.receive = receive) == NULL)
return (xm_perror (XERR_RCVR_FUNC, &xmfuncs));
/*------------------------------------------------
Initialize data for the first block and purge
all data from the receive buffer. Init the
number of bytes and blocks received and display
some useful info.
------------------------------------------------*/
next_block = last_block = 1;
xb.total_block_count = 0L;
xb.total_byte_count = 0L;
(*xmfuncs.dispstat) (0L, 0L, "");
PURGE_RECEIVER(receive);
/*------------------------------------------------
Attempt to transfer using CRC-16 error detection.
This involves sending the CRC begin character:
'C'.
------------------------------------------------*/
xb.crc_used = 1;
error = xm_send_n_wait (&crc_req,
&start_char,
&xmfuncs);
/*------------------------------------------------
If the sender did not respond to the CRC-16
transfer request, then attempt to transfer using
checksum error detection.
------------------------------------------------*/
if (error == XERR_SOH_TIMEOUT)
{
xb.crc_used = 0;
error = xm_send_n_wait (&checksum_req,
&start_char,
&xmfuncs);
}
/*------------------------------------------------
If begin transfer request failed, return error.
------------------------------------------------*/
if (error != XERR_OK)
return (error);
/*------------------------------------------------
If the starting character of the next block is
an EOT, then we have completed transferring the
file and we exit this loop. Otherwise, we init
the xmodem packet structure based on the first
character of the packet.
------------------------------------------------*/
while (start_char != EOT)
{
register int good_block; /* NZ if packet was OK */
error = xm_block_start (&xb,
start_char,
&xmfuncs);
if (error != XERR_OK)
return (error);
good_block = -1; /* assume packet will be OK */
/*------------------------------------------------
Receive the packet. If there was an error, then
NAK it. Otherwise, the packet was received OK.
------------------------------------------------*/
if (xm_recv_block (&xb, &xmfuncs) != XERR_OK)
{
good_block = 0; /* bad block */
}
/*------------------------------------------------
If this is the next expected packet, then append
it to the file and update the last and next
packet vars.
------------------------------------------------*/
else if (xb.block_num == next_block)
{
int bytes_written; /* bytes written for this block */
last_block = next_block;
next_block = (next_block + 1) % 256;
bytes_written = fwrite (xb.buffer, 1, xb.buflen, f);
xb.total_block_count++;
xb.total_byte_count += bytes_written;
(*xmfuncs.dispstat) (xb.total_block_count,
xb.total_byte_count,
NULL);
if (bytes_written != xb.buflen)
{
xm_send_cancel (transmit);
return (xm_perror (XERR_FILE_WRITE, &xmfuncs));
}
}
/*------------------------------------------------
If this is the previous packet, then the sender
did not receive our ACK to that packet and
resent it. This is OK. Just ACK the packet.
If the block number for this packet is completely
out of sequence, cancel the transmission and
return an error.
------------------------------------------------*/
else if (xb.block_num != last_block)
{
xm_send_cancel (transmit);
return (xm_perror (XERR_BLOCK_SEQUENCE, &xmfuncs));
}
/*------------------------------------------------
Here, good_block is non-zero if the block was
received and processed with no problems. If it
was a good block, then we send an ACK. A NAK is
sent for bad blocks.
------------------------------------------------*/
if (